package com.tencent.qf.web.aop;


import com.alibaba.fastjson.JSON;
import com.tencent.qf.common.pojo.HttpResult;
import com.tencent.qf.common.zhiyan.ZhiyanLogUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Objects;
import javax.servlet.http.HttpServletRequest;

import static com.tencent.qf.common.constants.WebConstants.START_TIME;
import static com.tencent.qf.common.constants.WebConstants.TRACE_ID;

/**
 * Copyright (C) 2022 Limited, a Tencent company. All rights reserved.
 * controller包切面，主要用于记录访问日志、返回httpResult设置traceId
 *
 * @author p_htaozhou@tencent.com
 * @create: 2022/9/16 10:51
 */
@Component
@Slf4j
@Aspect
@Order(1)
public class ControllerAspect {

    @Pointcut("execution(public * com.tencent.qf.*.controller..*.*(..)) ")
    public void recordLog() {

    }

    @Around("recordLog()")
    public Object around(ProceedingJoinPoint joinPoint) {
        long startTime = System.currentTimeMillis();
        MDC.put(START_TIME, String.valueOf(startTime));

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if(attributes == null){
            try {
                return joinPoint.proceed();
            } catch (Throwable e) {
                throw new RuntimeException(e);
            }
        }

        HttpServletRequest request = attributes.getRequest();
        //记录请求路径url
        log.info("url={}", request.getRequestURL());
        //记录请求方式method
        log.info("method={}", request.getMethod());
        //记录访问者ip
        log.info("ip={}", request.getRemoteAddr());
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        //记录访问的类方法
        log.info("class_method={}", methodSignature);
        //记录传递的参数
        log.info("args={}", joinPoint.getArgs());

        // traceId有可能是其他链路通过header传过来 traceId字段名需同步
        if (request.getHeader("Trace-Id") != null) {
            MDC.put(TRACE_ID, request.getHeader("Trace-Id"));
        } else {
            MDC.put(TRACE_ID, TraceContext.traceId());
        }
        log.info("traceId={}", MDC.get(TRACE_ID));

        try {
            return joinPoint.proceed();
        } catch (Throwable e) {
            ZhiyanLogUtil.sendLog(MDC.get(TRACE_ID), String.format("接口【%s】异常：%s", request.getRequestURL(), e.getMessage()));
            throw new RuntimeException(e);
        }
    }

    @AfterReturning(value = "recordLog()", returning = "response")
    public void after(Object response) {
        if (response instanceof HttpResult) {
            HttpResult<?> httpResult = (HttpResult<?>) response;
            httpResult.setTraceId(MDC.get(TRACE_ID));
            log.info("response:{}", JSON.toJSONString(response));
        } else {
            log.info("response:{}", Objects.isNull(response) ? "response is null !" : response.toString());
        }

        long endTime = System.currentTimeMillis();
        log.info("total time : {} ms", (endTime - Long.parseLong(MDC.get(START_TIME))));
    }
}
